#pragma once

#include <iostream>
#include <functional>
#include <string>
#include <cassert>
#include <unordered_map>
#include <vector>
#include "Sock.hpp"
#include "Log.hpp"
#include "Epoll.hpp"
#include "Protocol.hpp"

class TcpServer;
class Connection;

using func_t = std::function<void(Connection *)>;
using callback_t = std::function<void (Connection*, std::string &request)>; // 上层业务处理的方法

// 为了能够正常工作，常规的sock必须要有独立的接收缓冲区和发送缓冲区(写入)
class Connection // 一个链接类
{
public:
    Connection(int sock = -1)
        : _sock(sock), _tsvr(nullptr)
    {
    }
    void SetCallBack(func_t recv_cb, func_t send_cb, func_t except_cb)
    { // 设置三个回调方法
        _recv_cb = recv_cb;
        _send_cb = send_cb;
        _except_cb = except_cb;
    }
    ~Connection()
    {
    }

public:
    int _sock;       // 负责进行IO的文件描述符
    func_t _recv_cb; // 三个回调方法，是对_sock进行特定读写的对应方法
    func_t _send_cb;
    func_t _except_cb;

    std::string _inbuffer;  // 接收缓冲区&&发送缓冲区
    std::string _outbuffer; // 这两string暂时没有办法处理二进制流，文本是可以的

    TcpServer *_tsvr; // 设置对TcpServer的回指指针，对写事件的关心是按需打开
};

class TcpServer
{
    const static int gport = 8080;
    const static int gnum = 128;

public:
    TcpServer(int port = gport)
        : _port(port), _revs_num(gnum)
    {
        // 1. 创建listensock
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);

        // 2. 创建多路转接对象
        _poll.CreateEpoll();

        // 3. 添加listensock到服务器中 -> 三步(类的构造函数也能调用类的成员方法，走到函数体中对象已经存在了)
        // 后三个参数是函数对象，要bind绑定返回一个函数对象->类内函数有this指针，_1是预留的参数
        AddConnection(_listensock, std::bind(&TcpServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);

        // 4. 构建一个获取就绪事件的缓冲区
        _revs = new struct epoll_event[_revs_num];
    }
    void AddConnection(int sock, func_t recv_cb, func_t send_cb, func_t except_cb) // 把任意sock进行添加到TcpServer
    {
        Sock::SetNonBlock(sock); // ET模式要把sock设置成非阻塞 -> 在Sock.hpp中写成函数

        // 除了_listensock，后面还会存在大量的socket，每一个sock都必须被封装成为一个Connection
        // 当服务器中存在大量的Connection时，TcpServer需要将所有Connection进行管理：上面描述了，组织 -> unordered_map
        // 3.1 构建conn对象，封装sock
        Connection *conn = new Connection(sock);
        conn->SetCallBack(recv_cb, send_cb, except_cb);
        conn->_tsvr = this;

        // 3.2 添加sock到epoll中(任务通知)->要知道sock和事件(任何多路转接的服务器，一般只会打开读取事件，写入事件按需打开)
        _poll.AddSockToEpoll(sock, EPOLLIN | EPOLLET);

        // 3.3 将对应的Connection*对象指针添加到Connections映射表中(业务处理)
        _connections.insert(std::make_pair(sock, conn));
    }

    void Accepter(Connection *conn)
    {
        // logMessage(DEBUG, "Accepter been called");
        // 一定是listensock已经就绪了，此次读取不会阻塞，
        // 怎么保证，底层只有一个连接就绪呢 -> 循环，直到获取失败
        while (true)
        {
            std::string clientip;
            uint16_t clientport;
            int accept_errno = 0;
            // sock一定是常规的IO sock
            int sock = Sock::Accept(conn->_sock, &clientip, &clientport, &accept_errno);
            if (sock < 0) // 获取失败
            {
                if (accept_errno == EAGAIN || accept_errno == EWOULDBLOCK)
                    break;
                else if (accept_errno == EINTR) // 概率非常低
                    continue;
                else // accept失败
                {
                    logMessage(WARNING, "accept error, %d : %s", accept_errno, strerror(accept_errno));
                    break;
                }
            }
            else // (sock>=0)获取链接成功->将sock托管给TcpServer
            {
                AddConnection(sock, std::bind(&TcpServer::Recver, this, std::placeholders::_1),
                              std::bind(&TcpServer::Sender, this, std::placeholders::_1),
                              std::bind(&TcpServer::Excepter, this, std::placeholders::_1));
                logMessage(DEBUG, "accept client %s:%d success, add to epoll&&TcpServer success, sock: %d",
                           clientip.c_str(), clientport, sock);
            }
        }
    }

    void Recver(Connection *conn) // 读取一个正常的sock
    {
        const int num = 1024;
        bool err = false;
        // logMessage(DEBUG, "Recver event exists, Recver() been called");
        while (true)
        {
            char buffer[num];
            ssize_t n = recv(conn->_sock, buffer, sizeof(buffer) - 1, 0);
            if (n < 0)
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK) // 读取完毕了，正常的
                    break;
                else if (errno == EINTR) // 读取被中断了，重新开始读
                    continue;
                else // 真正读取失败 -> 交给异常回调
                {
                    logMessage(ERROR, "recv error, %d : %s", errno, strerror(errno));
                    conn->_except_cb(conn);
                    err = true;
                    break;
                }
            }
            else if (n == 0)
            {
                logMessage(DEBUG, "client[%d] quit, server close [%d]", conn->_sock, conn->_sock);
                conn->_except_cb(conn);
                err = true;
                break;
            }
            else // 读取成功
            {
                buffer[n] = 0;
                conn->_inbuffer += buffer; // 读取到的数据全部拼接到接收缓冲区
            }
        }
        logMessage(DEBUG, "conn->_inbuffer[sock: %d]: %s", conn->_sock, conn->_inbuffer.c_str());
        if (!err) // 如果错误码还是false就是正常break的
        {
            std::vector<std::string> messages;
            SpliteMessage(conn->_inbuffer, &messages);
            // 保证走到这里，就是一个完整报文
            for (auto &msg : messages)
            {    // 可以在这里将message封装成为task,然后push到任务队列,任务处理交给后端线程池,这里不处理
                _cb(conn, msg);
            }
        }
    }

   void Sender(Connection *conn)
    {
        while(true)
        {
            ssize_t n = send(conn->_sock, conn->_outbuffer.c_str(), conn->_outbuffer.size(), 0);
            if(n > 0) // 发送成功 -> 移除
            {
                conn->_outbuffer.erase(0, n);
                if(conn->_outbuffer.empty())  // 发完了 -> break
                    break;
            }
            else
            {
                if(errno == EAGAIN || errno == EWOULDBLOCK) // 缓冲区满了 -> break下次再发
                    break;
                else if(errno == EINTR) // 发送被中断 -> 重新发送
                    continue;
                else // 真正读取失败 -> 交给异常回调
                {
                    logMessage(ERROR, "send error, %d : %s", errno, strerror(errno));
                    conn->_except_cb(conn);
                    break;
                }
            }
        }
        // 不确定有没有发完，但是可以保证，如果没有出错，一定是发完了，或者发送条件不满足，下次再发
        if(conn->_outbuffer.empty()) // 发完了->不用关心写
            EnableReadWrite(conn, true, false);
        else // 发送条件不满足，下次再发
            EnableReadWrite(conn, true, true);
    }
    void EnableReadWrite(Connection *conn, bool readable, bool writeable) // 控制读写开关
    {            // 下面的三目：如readable为真就关心读事件,否则为0,writeable就关心写事件
        uint32_t events = ((readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0));
        bool res = _poll.CtrlEpoll(conn->_sock, events);
        assert(res);
    }

    void Excepter(Connection *conn)
    {
        if(!IsConnectionExists(conn->_sock)) // _sock不存在就返回
            return;
        bool res = _poll.DelFromEpoll(conn->_sock); // 1. 从epoll中移除
        assert(res);

        _connections.erase(conn->_sock); // 2. 从unorder_map中移除

        close(conn->_sock); // 3. 关闭sock

        delete conn; // 4. 释放 conn;
        logMessage(DEBUG, "Excepter 回收完毕所有的异常情况");
    }

    void Dispather(callback_t cb) // 根据就绪的事件，进行特定事件的派发
    {
        _cb = cb;
        while (true)
        {
            LoopOnce();
        }
    }
    void LoopOnce()
    {
        int n = _poll.WaitEpoll(_revs, _revs_num);
        for (int i = 0; i < n; i++) // 获取事件
        {
            int sock = _revs[i].data.fd;
            uint32_t revents = _revs[i].events;
            if (revents & EPOLLIN) // 读就绪
            {
                // if(Connection是存在并且_connections[sock]->_recv_cb被设置过)
                if (IsConnectionExists(sock) && _connections[sock]->_recv_cb != nullptr)
                    _connections[sock]->_recv_cb(_connections[sock]); // 调用读事件的回调
            }
            if (revents & EPOLLOUT) // 写就绪
            {
                // if(Connection是存在并且_connections[sock]->_send_cb被设置过)
                if (IsConnectionExists(sock) && _connections[sock]->_send_cb != nullptr)
                    _connections[sock]->_send_cb(_connections[sock]); // 调用写事件的回调
            }
        }
    }
    bool IsConnectionExists(int sock) // 判定Connection是否存在
    {
        auto iter = _connections.find(sock);
        if (iter == _connections.end())
            return false;
        else
            return true;
    }
    ~TcpServer()
    {
        if (_listensock >= 0)
            close(_listensock);
        if (_revs)
            delete[] _revs;
    }

private:
    int _listensock;
    int _port;
    Epoll _poll;
    std::unordered_map<int, Connection *> _connections; // 管理：sock映射到Connection
    struct epoll_event *_revs;                          // 就绪事件缓冲区,就绪的文件描述符投递到这里
    int _revs_num;                                      // 就绪事件缓冲区大小

    callback_t _cb; // 处理上层的业务的回调函数
};